/**
 * author: volcaner
 * create: 04/28/2020
 */


/** _toString
 * Get the raw type string of a value, e.g., [object Object].
 */
const _toString = Object.prototype.toString;



/** _getDeepParamVal
 * [_getDeepParamVal 传递 paramKeys 数组，在 obj 对象中查找到对应的值]
 * paramKeys: 为 obj 的参数层级
 * [
 *  如：
 *    obj = {
 *      aaa: {
 *        bbb: '我是值'
 *      }
 *    }
 *
 *    paramsKey = [ 'aaa', 'bbb' ]
 *
 *    return obj['aaa']['bbb']
 * ]
 * @使用场景: cardLists
 * @return: val / undefined
 */
export const _getDeepParamVal = (obj, paramKeys) => {
  // console.log('_getDeepParamVal: ');
  // let val = obj;
  // val = paramKeys.length <=  0 ? val :
  //   this._getDeepParamVal( obj[ paramKeys.shift() ],  paramKeys );

  let val;
  try {
    if( !( isObject(obj) || isArray(obj) )
      && ( !isArray(paramKeys) || paramKeys.length <= 0 ) ) throw new Error('EndIterative');

    const key = paramKeys.shift();
    if( !isHasOwnProperty(obj, key) ) throw new Error('EndIterative');

    if( paramKeys.length <= 0 ) val = _.cloneDeep(obj[key]);
    else val = _getDeepParamVal(obj[key], paramKeys);
  } catch(e) {
    // 不存在 key,结束迭代
    console.log('Error: ', e.message);
    val = e;
  }

  return val;
};

/** _getDataType
 * [_getDataType description]
 * @param  {[type]} val [description]
 * @return {[type]}     [description]
 */
export const _getDataType = (val) => {
  return _toString.call(val);
};

/** isNumber
 * [isNumber description]
 * @param  {[type]}  val [description]
 * @return {Boolean}     [description]
 */
export const isNumber = (val) => {
  return _toString.call(val) === "[object Number]";
};

/** isObject
 * [isObject description]
 * @param  {[type]}  val [description]
 * @return {Boolean}     [description]
 */
export const isObject = (val) => {
  return _toString.call(val) === "[object Object]";
};

/** isFunction
 * [isFunction description]
 * @param  {[type]}  val [description]
 * @return {Boolean}     [description]
 */
export const isFunction = (val) => {
  return _toString.call(val) === "[object Function]";
};

/** isArray
 * [isArray description]
 * @param  {[type]}  val [description]
 * @return {Boolean}     [description]
 */
export const isArray = (val) => {
  return _toString.call(val) === "[object Array]";
};

/** isString
 * [isString description]
 * @param  {[type]}  val [description]
 * @return {Boolean}     [description]
 */
export const isString = (val) => {
  return _toString.call(val) === "[object String]";
};

/** isUndefined
 * [isUndefined description]
 * @param  {[type]}  val [description]
 * @return {Boolean}     [description]
 */
export const isUndefined = (val) => {
  return _toString.call(val) === "[object Undefined]";
};

/** isAbsUndef
 * typeof 较安全:
 *  1. 未申明(Uncaught ReferenceError: is not defined)
 *  2. undefined
 *  3. null
 * @param  {[type]}  val [description]
 * @return {Boolean}     [description]
 */
export const isAbsUndef = (val) => {
  return typeof val === 'undefined' || val === null;
};

/** isHasOwnProperty
 * [isHasOwnProperty description]
 * @param  {[type]}  obj [description]
 * @param  {[type]}  key [description]
 * @return {Boolean}     [description]
 */
export const isHasOwnProperty = (obj, key) => {
  return !isAbsUndef(obj) && Object.prototype.hasOwnProperty.call(obj, key);
};

/** isArrayEquals
 * [isArrayEquals description]
 * @param  {[type]}  arr1 [description]
 * @param  {[type]}  arr2 [description]
 * @return {Boolean}      [description]
 */
export const isArrayEquals = (arr1, arr2) => {
  if(!(arr1 || arr2)) return false;

  if(arr1.length != arr2.length) return false;

  for(let i = 0, l = arr1.length; i < l; i++) {
    if(arr1[i] instanceof Array && arr2[i] instanceof Array) {
      if(!isArrayEquals(arr1[i], arr2[i])) return false;
    }
    else if(arr1[i] instanceof Object && arr2[i] instanceof Object) {
      if(!isObjectEquals(arr1[i], arr2[i])) return false;
    }
    else if(arr1[i] != arr2[i]) {
      return false
    };
  }

  return true;
};

/** isObjectEquals
 * [isObjectEquals description]
 * @param  {[type]}  object1 [description]
 * @param  {[type]}  object1 [description]
 * @return {Boolean}         [description]
 */
export const isObjectEquals = (object1, object2) => {
  const keys1 = Object.keys(object1);
  const keys2 = Object.keys(object2);

  if (keys1.length !== keys2.length) return false;

  for (let index = 0; index < keys1.length; index++) {
    const val1 = object1[keys1[index]];
    const val2 = object2[keys2[index]];
    const areObjects = isObject(val1) && isObject(val2);
    if (areObjects && !isObjectEquals(val1, val2) || !areObjects && val1 !== val2) return false;
  }

  return true;
};

/** WindowClient
 * [WindowClient description]
 */
export const _getWindowClient = () => {
  if(window.innerWidth != null) {  // ie9 +  最新浏览器
    return {
      width: window.innerWidth,
      height: window.innerHeight
    }
  }
  else if(document.compatMode === "CSS1Compat") {  // 标准浏览器
    return {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight
    }
  }
  return {   // 怪异浏览器
    width: document.body.clientWidth,
    height: document.body.clientHeight
  }
};

/** _cloneDeep
 * [_cloneDeep 深拷贝]
 * @param  {[type]} val [description]
 * @return {[type]}     [description]
 */
export const _cloneDeep = (val) => {
  if (isAbsUndef(val) || (!isArray(val) && !isObject(val))) return val;
  let _newVal;
  const _isArr = isArray(val);
  if (_isArr) {
    _newVal = [];
    let i = val.length;
    while (i--) {
      _newVal.unshift(_cloneDeep(val[i]));
    }
  } else {
    _newVal = {};
    let _keys = Object.keys(val);
    let j = _keys.length;
    while (j--) {
      _newVal[_keys[j]] = _cloneDeep(val[_keys[j]]);
    }
  }

  return _newVal;
};
